﻿using AccelerateSensor.SocketServer;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AccelerateSensor.Model.Gateway;
using AccelerateSensor.Model.Node;
using AccelerateSensor.Service.DbProxy.InfluxDb;
using AccelerateSensor.Service.DbProxy.SQLite;

namespace AccelerateSensor.Service
{
    public class AccelerateSensorService : IDataObserver
    {
        public event Action StartFailedEvent = () => { };
        public event Action<GatewayInfo> GatewayInfoChangedEvent = (gatewayInfo) => { };
        public event Action<NodeInfo> NodeInfoChangedEvent = (nodeInfo) => { };
        public event Action<NodeData> NodeDataChangedEvent = (data) => { };

        public List<GatewayInfo> GatewayInfoList => _dataHelper.GetGatewayList();

        private readonly DataHelper _dataHelper;
        private readonly InfluxDbProxy _influxDbProxy;
        // ReSharper disable once IdentifierTypo
        private readonly SqliteDbProxy _sqliteDbProxy;

        public void Startup()
        {
            //在线程池中启动服务
            ThreadPool.QueueUserWorkItem((state) =>
            {
                if (!SocketServerManager.Instance.Startup())
                {
                    StartFailedEvent?.Invoke();
                    return;
                }

                _dataHelper.Init(SocketServerManager.Instance);
                _influxDbProxy.Init();
                _sqliteDbProxy.Init();
            });
        }

        public void Shutdown()
        {
            SocketServerManager.Instance.Shutdown();
            _dataHelper.UnInit(SocketServerManager.Instance);
        }

        #region Data Interface

        public List<GatewayInfo> GetGatewayInfoList()
        {
            return _sqliteDbProxy.GetGatewayInfoList();
        }

        public void UpdateGatewayInfo(GatewayInfo gatewayInfo)
        {
            _sqliteDbProxy.UpdateGatewayInfo(gatewayInfo);
        }

        public List<NodeInfo> GetNodeList(string gatewayUuid)
        {
            return _sqliteDbProxy.GetNodeList(gatewayUuid);
        }

        public void UpdateNodeInfo(NodeInfo nodeInfo)
        {
            _sqliteDbProxy.UpdateNodeInfo(nodeInfo);
        }

        public async Task<int> GetNodeDataCountAsync(string nodeUuid)
        {
            return await _influxDbProxy.GetNodeDataCountAsync(nodeUuid);
        }

        public async Task<List<NodeData>> GetPageNodeDataAsync(
            string nodeUuid, int countPerPage, int curPage, int count)
        {
            return await _influxDbProxy.GetPageNodeDataAsync(nodeUuid, countPerPage, curPage, count);
        }

        public async Task<List<NodeData>> GetNodeDataAsync(string nodeUuid, DateTime start, DateTime stop)
        {
            return await _influxDbProxy.GetNodeDataAsync(nodeUuid, start, stop);
        }

        #endregion

        #region IDataObserver

        public void GatewayInfoChanged(GatewayInfo gatewayInfo)
        {
            UpdateGatewayInfo(gatewayInfo);
            GatewayInfoChangedEvent?.Invoke(gatewayInfo);
        }

        public void NodeInfoChanged(NodeInfo nodeInfo)
        {
            UpdateNodeInfo(nodeInfo);
            NodeInfoChangedEvent?.Invoke(nodeInfo);
        }

        public void NodeDataChanged(NodeData nodeData)
        {
            //添加到数据库
            _influxDbProxy.AddNodeData(nodeData);

            //更新节点、网关
            _sqliteDbProxy.UpdateNodeInfo(nodeData.NodeUuid, nodeData.UpdateTime);
            _sqliteDbProxy.UpdateGatewayInfo(nodeData.NodeUuid, nodeData.UpdateTime);

            //通知节点数据更新
            NodeDataChangedEvent?.Invoke(nodeData);
        }

        #endregion

        #region Singleton Pattern

        private static AccelerateSensorService _instance;
        private static readonly object LockHelper = new object();

        private AccelerateSensorService()
        {
            _dataHelper = new DataHelper(this);
            _influxDbProxy = new InfluxDbProxy();
            _sqliteDbProxy = new SqliteDbProxy();
        }

        public static AccelerateSensorService Instance
        {
            get
            {
                if (_instance != null)
                {
                    return _instance;
                }

                lock (LockHelper)
                {
                    _instance = _instance ?? new AccelerateSensorService();
                }

                return _instance;
            }
        }

        #endregion
    }
}
